Coverage Report

Created: 2024-12-19 06:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
D:\a\tools.proto\tools.proto\compiler\src\api\core\loader.rs
Line
Count
Source
1
// Copyright (c) 2024, BlockProject 3D
2
//
3
// All rights reserved.
4
//
5
// Redistribution and use in source and binary forms, with or without modification,
6
// are permitted provided that the following conditions are met:
7
//
8
//     * Redistributions of source code must retain the above copyright notice,
9
//       this list of conditions and the following disclaimer.
10
//     * Redistributions in binary form must reproduce the above copyright notice,
11
//       this list of conditions and the following disclaimer in the documentation
12
//       and/or other materials provided with the distribution.
13
//     * Neither the name of BlockProject 3D nor the names of its contributors
14
//       may be used to endorse or promote products derived from this software
15
//       without specific prior written permission.
16
//
17
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29
use crate::api::core::Error;
30
use crate::compiler::util::imports::{ImportSolver, ProtocolStore};
31
use crate::{compiler, model};
32
use bp3d_debug::{error, trace};
33
use std::borrow::Cow;
34
use std::path::Path;
35
36
pub struct Loader<'a> {
37
    models: Vec<(&'a str, model::Protocol)>,
38
    max_iterations: usize,
39
}
40
41
impl Default for Loader<'_> {
42
2
    fn default() -> Self {
43
2
        Self::new(16)
44
2
    }
45
}
46
47
impl<'a> Loader<'a> {
48
22
    pub fn new(max_iterations: usize) -> Self {
49
22
        Self {
50
22
            models: Vec::new(),
51
22
            max_iterations,
52
22
        }
53
22
    }
54
55
2
    pub fn load_from_folder(&mut self, path: impl AsRef<Path>, package: &'a str) -> Result<(), Error> {
56
40
        for a in 
std::fs::read_dir(path).map_err(Error::Io)2
?0
{
57
40
            let file = a.map_err(Error::Io)
?0
;
58
40
            if file.file_name().as_encoded_bytes().ends_with(b".json5") {
  Branch (58:16): [True: 18, False: 2]
  Branch (58:16): [Folded - Ignored]
  Branch (58:16): [True: 18, False: 2]
  Branch (58:16): [Folded - Ignored]
59
36
                self.load_from_file(file.path(), package)
?0
60
4
            }
61
        }
62
2
        Ok(())
63
2
    }
64
65
36
    pub fn load_from_file(&mut self, path: impl AsRef<Path>, package: &'a str) -> Result<(), Error> {
66
36
        let content = std::fs::read_to_string(path).map_err(Error::Io)
?0
;
67
36
        self.load_from_string(content, package)
68
36
    }
69
70
56
    pub fn load_from_string(&mut self, content: impl AsRef<str>, package: &'a str) -> Result<(), Error> {
71
56
        let model: model::Protocol = json5::from_str(content.as_ref()).map_err(Error::Model)
?0
;
72
56
        if model.imports.as_ref().map(|v| 
v.len()10
).unwrap_or_default() > 0 {
  Branch (72:12): [True: 5, False: 13]
  Branch (72:12): [Folded - Ignored]
  Branch (72:12): [True: 5, False: 13]
  Branch (72:12): [Folded - Ignored]
  Branch (72:12): [True: 0, False: 5]
  Branch (72:12): [True: 0, False: 1]
  Branch (72:12): [True: 0, False: 1]
  Branch (72:12): [True: 0, False: 4]
  Branch (72:12): [True: 0, False: 3]
  Branch (72:12): [True: 0, False: 5]
  Branch (72:12): [True: 0, False: 1]
73
10
            self.models.insert(0, (package, model));
74
46
        } else {
75
46
            self.models.push((package, model));
76
46
        }
77
56
        Ok(())
78
56
    }
79
80
1
    pub fn exclude(&mut self, name: &str) {
81
18
        self.models.retain(|(_, model)| model.name != name);
82
1
    }
83
84
22
    pub fn compile<T: ImportSolver>(mut self, solver: &T) -> Result<ProtocolStore<T>, Error> {
85
22
        let mut protocols = ProtocolStore::new(solver);
86
22
        let mut iterations = self.max_iterations;
87
63
        while !self.models.is_empty() && 
iterations > 061
{
  Branch (87:15): [True: 20, False: 1]
  Branch (87:42): [True: 20, False: 0]
  Branch (87:15): [Folded - Ignored]
  Branch (87:42): [Folded - Ignored]
  Branch (87:15): [True: 21, False: 1]
  Branch (87:42): [True: 21, False: 0]
  Branch (87:15): [Folded - Ignored]
  Branch (87:42): [Folded - Ignored]
  Branch (87:15): [True: 5, False: 0]
  Branch (87:42): [True: 5, False: 0]
  Branch (87:15): [True: 1, False: 0]
  Branch (87:42): [True: 1, False: 0]
  Branch (87:15): [True: 1, False: 0]
  Branch (87:42): [True: 1, False: 0]
  Branch (87:15): [True: 4, False: 0]
  Branch (87:42): [True: 4, False: 0]
  Branch (87:15): [True: 3, False: 0]
  Branch (87:42): [True: 3, False: 0]
  Branch (87:15): [True: 5, False: 0]
  Branch (87:42): [True: 5, False: 0]
  Branch (87:15): [True: 1, False: 0]
  Branch (87:42): [True: 1, False: 0]
88
61
            let (package, model) = self.models.pop().unwrap();
89
61
            trace!({imports=?model.imports}, "Solving imports for model {}", model.name);
90
61
            if model
  Branch (90:16): [True: 3, False: 17]
  Branch (90:16): [Folded - Ignored]
  Branch (90:16): [True: 3, False: 18]
  Branch (90:16): [Folded - Ignored]
  Branch (90:16): [True: 0, False: 5]
  Branch (90:16): [True: 0, False: 1]
  Branch (90:16): [True: 0, False: 1]
  Branch (90:16): [True: 0, False: 4]
  Branch (90:16): [True: 0, False: 3]
  Branch (90:16): [True: 0, False: 5]
  Branch (90:16): [True: 0, False: 1]
91
61
                .imports
92
61
                .as_ref()
93
61
                .map(|v| {
94
44
                    v.iter().any(|v| {
95
44
                        let full_name = if package.is_empty() {
  Branch (95:44): [True: 22, False: 0]
  Branch (95:44): [Folded - Ignored]
  Branch (95:44): [True: 22, False: 0]
  Branch (95:44): [Folded - Ignored]
  Branch (95:44): [True: 0, False: 0]
  Branch (95:44): [True: 0, False: 0]
  Branch (95:44): [True: 0, False: 0]
  Branch (95:44): [True: 0, False: 0]
  Branch (95:44): [True: 0, False: 0]
  Branch (95:44): [True: 0, False: 0]
  Branch (95:44): [True: 0, False: 0]
96
44
                            Cow::Borrowed(&v.protocol)
97
                        } else {
98
0
                            Cow::Owned(format!("{}::{}", package, v.protocol))
99
                        };
100
44
                        protocols.get(&full_name).is_none()
101
44
                    })
102
61
                })
103
61
                .unwrap_or_default()
104
            {
105
6
                self.models.insert(0, (package, model));
106
6
                iterations -= 1;
107
6
                continue;
108
55
            }
109
55
            let 
proto35
= compiler::Protocol::from_model(model, &protocols, package).map_err(Error::Compiler)
?20
;
110
35
            protocols.insert(proto);
111
        }
112
2
        if iterations == 0 && 
!self.models.is_empty()0
{
  Branch (112:12): [True: 0, False: 1]
  Branch (112:31): [True: 0, False: 0]
  Branch (112:12): [Folded - Ignored]
  Branch (112:31): [Folded - Ignored]
  Branch (112:12): [True: 0, False: 1]
  Branch (112:31): [True: 0, False: 0]
  Branch (112:12): [Folded - Ignored]
  Branch (112:31): [Folded - Ignored]
  Branch (112:12): [True: 0, False: 0]
  Branch (112:31): [True: 0, False: 0]
  Branch (112:12): [True: 0, False: 0]
  Branch (112:31): [True: 0, False: 0]
  Branch (112:12): [True: 0, False: 0]
  Branch (112:31): [True: 0, False: 0]
  Branch (112:12): [True: 0, False: 0]
  Branch (112:31): [True: 0, False: 0]
  Branch (112:12): [True: 0, False: 0]
  Branch (112:31): [True: 0, False: 0]
  Branch (112:12): [True: 0, False: 0]
  Branch (112:31): [True: 0, False: 0]
  Branch (112:12): [True: 0, False: 0]
  Branch (112:31): [True: 0, False: 0]
113
0
            error!(
114
0
                "Failed to solve protocol import order in {} iterations, {} model(s) could not be solved...",
115
0
                self.max_iterations,
116
0
                self.models.len()
117
0
            );
118
0
            return Err(Error::SolverMaxIterations);
119
2
        }
120
2
        Ok(protocols)
121
22
    }
122
}